Gabriel Chaix 50% | Elsa Chevrot 50%

TD 8/9 : Analyse des données

Demandes de valeurs foncières

Dataset OpenData :

data.gouv.fr/demandes-de-valeurs-foncieres


Il s'agit des transactions immobilières intervenues au cours des cinq dernières années sur le territoire métropolitain et les DOM-TOM, à l’exception de l’Alsace, de la Moselle et de Mayotte. Les données contenues sont issues des actes notariés et des informations cadastrales.


Mini rapport :

blablablabalbalb

abla lbalba lb albalblbl abllblab lblbl


Librairies

Install

%load_ext pretty_jupyter
%load_ext jinja2
The pretty_jupyter extension is already loaded. To reload it, use:
  %reload_ext pretty_jupyter
The jinja2 module is not an IPython extension.
# install calmap pour colab
#! pip install calmap
#mettre à jour plotly pour colab
#!pip install plotly==4.5.2
#!pip install plotly
#!pip install geopandas
#!pip install jinja2 

Imports

# librairies essentielles
import json
import requests
import random
from urllib.request import urlopen
from  collections import Counter

# analyse et stockage
import numpy as np
import pandas as pd

# visualisation
import warnings
warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import geopandas as gpd
colors1 = ['#DAF7A6', '#FFC300', '#FF5733', '#C70039', '#900C3F', '#581845']
colors2 = ["#e60049", "#0bb4ff", "#50e991", "#e6d800", "#9b19f5", "#ffa300", "#dc0ab4", "#b3d4ff", "#00bfa0"]
colors3 = ["#1984c5", "#22a7f0", "#63bff0", "#a7d5ed", "#e2e2e2", "#e1a692", "#de6e56", "#e14b31", "#c23728"]

I ] Chargement

df = pd.read_csv('https://static.data.gouv.fr/resources/demandes-de-valeurs-foncieres/20230405-160733/valeursfoncieres-2022.txt', sep = '|')
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3803885 entries, 0 to 3803884
Data columns (total 43 columns):
 #   Column                      Dtype  
---  ------                      -----  
 0   Identifiant de document     float64
 1   Reference document          float64
 2   1 Articles CGI              float64
 3   2 Articles CGI              float64
 4   3 Articles CGI              float64
 5   4 Articles CGI              float64
 6   5 Articles CGI              float64
 7   No disposition              int64  
 8   Date mutation               object 
 9   Nature mutation             object 
 10  Valeur fonciere             object 
 11  No voie                     float64
 12  B/T/Q                       object 
 13  Type de voie                object 
 14  Code voie                   object 
 15  Voie                        object 
 16  Code postal                 float64
 17  Commune                     object 
 18  Code departement            object 
 19  Code commune                int64  
 20  Prefixe de section          float64
 21  Section                     object 
 22  No plan                     int64  
 23  No Volume                   object 
 24  1er lot                     object 
 25  Surface Carrez du 1er lot   object 
 26  2eme lot                    object 
 27  Surface Carrez du 2eme lot  object 
 28  3eme lot                    object 
 29  Surface Carrez du 3eme lot  object 
 30  4eme lot                    float64
 31  Surface Carrez du 4eme lot  object 
 32  5eme lot                    float64
 33  Surface Carrez du 5eme lot  object 
 34  Nombre de lots              int64  
 35  Code type local             float64
 36  Type local                  object 
 37  Identifiant local           float64
 38  Surface reelle bati         float64
 39  Nombre pieces principales   float64
 40  Nature culture              object 
 41  Nature culture speciale     object 
 42  Surface terrain             float64
dtypes: float64(17), int64(4), object(22)
memory usage: 1.2+ GB
# formatage des noms des colonnes
df = df.rename(columns=lambda x: x.replace(' ', '_').lower())

II ] Nettoyage

#Vérifier les parts des données manquantes dans la base brutes
df.isnull().sum()/len(df)*100
identifiant_de_document       100.000000
reference_document            100.000000
1_articles_cgi                100.000000
2_articles_cgi                100.000000
3_articles_cgi                100.000000
4_articles_cgi                100.000000
5_articles_cgi                100.000000
no_disposition                  0.000000
date_mutation                   0.000000
nature_mutation                 0.000000
valeur_fonciere                 0.649888
no_voie                        34.733621
b/t/q                          95.374019
type_de_voie                   36.984294
code_voie                       1.026398
voie                            1.029290
code_postal                     1.029816
commune                         0.000000
code_departement                0.000000
code_commune                    0.000000
prefixe_de_section             95.824295
section                         0.004075
no_plan                         0.000000
no_volume                      99.765792
1er_lot                        66.631142
surface_carrez_du_1er_lot      90.332568
2eme_lot                       89.535278
surface_carrez_du_2eme_lot     96.741752
3eme_lot                       98.134670
surface_carrez_du_3eme_lot     99.635662
4eme_lot                       99.402611
surface_carrez_du_4eme_lot     99.911880
5eme_lot                       99.744130
surface_carrez_du_5eme_lot     99.967481
nombre_de_lots                  0.000000
code_type_local                39.918478
type_local                     39.918478
identifiant_local             100.000000
surface_reelle_bati            39.973396
nombre_pieces_principales      39.973396
nature_culture                 33.830912
nature_culture_speciale        95.934262
surface_terrain                33.830912
dtype: float64
# suppression des attributs non nécessaire
df = df.drop(['identifiant_de_document',
              'reference_document',
              '1_articles_cgi',
              '2_articles_cgi',
              '3_articles_cgi',
              '4_articles_cgi',
              '5_articles_cgi',
              'prefixe_de_section',
              'no_volume',
              '3eme_lot',
              '4eme_lot',
              '5eme_lot',
              'identifiant_local',
              'nature_culture_speciale',
              ],axis= 1)
# suppression des doubles
df = df.drop_duplicates()
# suppression des ligne null
df = df.dropna(how="all")
# correction des types de données
df['date_mutation'] = pd.to_datetime(df['date_mutation'])
df['nature_mutation'] = df['nature_mutation'].astype('category')
df['valeur_fonciere'] = df['valeur_fonciere'].str.replace(',', '.').astype('float')
df['no_voie'] = df['no_voie'].astype('Int32')
df['b/t/q'] = df['b/t/q'].astype('category')
df['code_postal'] = df['code_postal'].astype('Int32')
df['code_commune'] = df['code_commune'].astype('int32')
df['no_plan'] = df['no_plan'].astype('int32')
df['1er_lot'] = df['1er_lot'].astype('category')
df['2eme_lot'] = df['2eme_lot'].astype('category')
df['surface_carrez_du_1er_lot'] = df['surface_carrez_du_1er_lot'].str.replace(',', '.').astype('float')
df['surface_carrez_du_2eme_lot'] = df['surface_carrez_du_2eme_lot'].str.replace(',', '.').astype('float')
df['surface_carrez_du_3eme_lot'] = df['surface_carrez_du_3eme_lot'].str.replace(',', '.').astype('float')
df['surface_carrez_du_4eme_lot'] = df['surface_carrez_du_4eme_lot'].str.replace(',', '.').astype('float')
df['surface_carrez_du_5eme_lot'] = df['surface_carrez_du_5eme_lot'].str.replace(',', '.').astype('float')
df['nombre_de_lots'] = df['nombre_de_lots'].astype('int32')
df['code_type_local'] = df['code_type_local'].astype('Int32')
df['type_local'] = df['type_local'].astype('category')
df['surface_reelle_bati'] = df['surface_reelle_bati'].astype('float')
df['nombre_pieces_principales'] = df['nombre_pieces_principales'].astype('Int32')
df['nature_culture'] = df['nature_culture'].astype('category')
df['surface_terrain'] = df['surface_terrain'].astype('float')
#suppression des valeur_fonciere null
df = df[df['valeur_fonciere'] > 0]
df['surface_carrez_du_1er_lot'].fillna(0, inplace=True)
df['surface_carrez_du_2eme_lot'].fillna(0, inplace=True)
df['surface_carrez_du_3eme_lot'].fillna(0, inplace=True)
df['surface_carrez_du_4eme_lot'].fillna(0, inplace=True)
df['surface_carrez_du_5eme_lot'].fillna(0, inplace=True)
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3509650 entries, 0 to 3803884
Data columns (total 29 columns):
 #   Column                      Dtype         
---  ------                      -----         
 0   no_disposition              int64         
 1   date_mutation               datetime64[ns]
 2   nature_mutation             category      
 3   valeur_fonciere             float64       
 4   no_voie                     Int32         
 5   b/t/q                       category      
 6   type_de_voie                object        
 7   code_voie                   object        
 8   voie                        object        
 9   code_postal                 Int32         
 10  commune                     object        
 11  code_departement            object        
 12  code_commune                int32         
 13  section                     object        
 14  no_plan                     int32         
 15  1er_lot                     category      
 16  surface_carrez_du_1er_lot   float64       
 17  2eme_lot                    category      
 18  surface_carrez_du_2eme_lot  float64       
 19  surface_carrez_du_3eme_lot  float64       
 20  surface_carrez_du_4eme_lot  float64       
 21  surface_carrez_du_5eme_lot  float64       
 22  nombre_de_lots              int32         
 23  code_type_local             Int32         
 24  type_local                  category      
 25  surface_reelle_bati         float64       
 26  nombre_pieces_principales   Int32         
 27  nature_culture              category      
 28  surface_terrain             float64       
dtypes: Int32(4), category(6), datetime64[ns](1), float64(8), int32(3), int64(1), object(6)
memory usage: 589.6+ MB
df.head()
no_disposition date_mutation nature_mutation valeur_fonciere no_voie b/t/q type_de_voie code_voie voie code_postal ... surface_carrez_du_3eme_lot surface_carrez_du_4eme_lot surface_carrez_du_5eme_lot nombre_de_lots code_type_local type_local surface_reelle_bati nombre_pieces_principales nature_culture surface_terrain
0 1 2022-03-01 Vente 55000.0 13 NaN RUE 2280 DE LA LIBERTE 1000 ... 0.0 0.0 0.0 1 2 Appartement 24.0 1 NaN NaN
1 1 2022-03-01 Vente 143000.0 <NA> NaN NaN B010 CHAMP COCHET 1480 ... 0.0 0.0 0.0 0 <NA> NaN NaN <NA> S 84.0
2 1 2022-03-01 Vente 143000.0 <NA> NaN NaN B010 CHAMP COCHET 1480 ... 0.0 0.0 0.0 0 <NA> NaN NaN <NA> S 88.0
3 1 2022-03-01 Vente 143000.0 98 NaN RTE 0055 DE LA DOMBES 1480 ... 0.0 0.0 0.0 1 2 Appartement 140.0 3 NaN NaN
4 1 2022-04-01 Vente 300.0 <NA> NaN NaN B031 AUX PIERRES 1480 ... 0.0 0.0 0.0 0 <NA> NaN NaN <NA> T 510.0

5 rows × 29 columns

III ] Interprétations

Générales

  1. Quelle est la part de maison, d'appartement, ect.. dans le dataset?
# Quelle est la part de maison, d'appartement, ect.. dans le dataset?
types = df['type_local'].value_counts(dropna = False, normalize = True).head()
plt.figure(figsize=(8,8))
plt.pie(types.values, labels=types.index, colors = colors2, startangle=65)
plt.title(label= 'Parts des types de biens')
plt.legend(loc = 4)
<matplotlib.legend.Legend at 0x7fe89424f820>
  1. Prix au mètre carré en fonction du type de local
# Prix au mètre carré en fonction du type de local
pm2 = df[(df['nombre_de_lots']<6) & ((df['surface_carrez_du_1er_lot'] + df['surface_carrez_du_2eme_lot'] + df['surface_carrez_du_3eme_lot'] + df['surface_carrez_du_4eme_lot'] + df['surface_carrez_du_5eme_lot']) > 0)]
pm2['surface_totale'] = pm2['surface_carrez_du_1er_lot'] + pm2['surface_carrez_du_2eme_lot'] + pm2['surface_carrez_du_3eme_lot'] + pm2['surface_carrez_du_4eme_lot'] + pm2['surface_carrez_du_5eme_lot']
pm2['prix_m2'] = pm2['valeur_fonciere'] / pm2['surface_totale']
sns.set(rc={'figure.figsize':(40,30)})
sns.color_palette()
sns.catplot(x="type_local", y="prix_m2", jitter=True, data=pm2, kind="strip", height=8, aspect=1.5, palette="Set2")
#sns.stripplot(pm2['type_local'],pm2['prix_m2'],jitter=True)
#pm2.loc[:,['type_local','prix_m2']].plot(kind='scatter',x='type_local',y='prix_m2')
<seaborn.axisgrid.FacetGrid at 0x7fe9517629a0>
  1. Comparaison de plusieurs types de local
prixlocal = df.loc[df['type_local'].notna() & df['surface_terrain'].notna() & df['surface_terrain'] >= 1 & df['valeur_fonciere'].notna(),("surface_terrain","valeur_fonciere","type_local")]
prixlocal['prix_m2_sur_le_terrain'] = prixlocal['valeur_fonciere']/prixlocal['surface_terrain']
prixlocal['valeur_fonciere'] = prixlocal['valeur_fonciere']/1000
prixlocal.groupby(['type_local']).mean().plot.bar(title = 'Comparaison de différents types de local',figsize=(20,5))
<AxesSubplot:title={'center':'Comparaison de différents types de local'}, xlabel='type_local'>
  1. Surface du terrain par département
fig = plt.figure(4,figsize = (30,5))
axis = fig.add_subplot(1, 1, 1)
axis.set_title('Surface du terrain en fonction du département')
axis.set_xlabel("Département")
axis.set_ylabel("Surface du terrain")
chmp = df.loc[df["code_departement"].notna(),("surface_terrain","code_departement")]
gb = chmp.groupby("code_departement",dropna= False).mean()['surface_terrain'].reset_index()

axis.bar(gb["code_departement"].astype(str), gb["surface_terrain"])
plt.xticks(rotation=90)
fig.show()
  1. Quelle est la valeur foncière moyenne par département en 2022 (bar plot) ?
#Quelle est la valeur foncière moyenne par departement en utilisant un bar plot ?
grouped_vf_dept = df.groupby('code_departement')['valeur_fonciere'].mean().reset_index()
grouped_vf_dept['code_departement'] = grouped_vf_dept['code_departement'].astype('string')
fig = px.bar(grouped_vf_dept, y='valeur_fonciere',
             x='code_departement',
             text_auto='.2s')
fig.update_layout(title="Valeur foncière moyenne par département", 
                  yaxis_title='Valeur foncière moyenne (€)', 
                  xaxis_title='Département');
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{#fig.to_html(include_plotlyjs=False,full_html=False)#}
  1. Quelle est la valeur foncière moyenne par département en 2022 (geojson et choropleth) ?
#Quelle est la valeur foncière moyenne par département en 2022 (geojson et choropleth) ?
geojson_url = "https://france-geojson.gregoiredavid.fr/repo/departements.geojson"
geojson_data = requests.get(geojson_url).json()

fig = px.choropleth(grouped_vf_dept, 
                    geojson=geojson_data, 
                    locations='code_departement', 
                    color='valeur_fonciere',
                    color_continuous_scale='pinkyl',
                    featureidkey='properties.code',
                    projection="mercator",
                    title='Valeur foncière moyenne par départements')
fig.update_geos(fitbounds="locations", visible=False)
fig.update_layout(height=600, width=800);
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }
  1. Quelle est la valeur foncière moyenne par pays, par département et par commune (treemap) ?
# Quelle est la valeur foncière moyenne par pays, par département (treemap) ?
df_avg = df.groupby(['code_departement'])['valeur_fonciere'].mean().reset_index()
fig = px.treemap(df_avg,
                 path=[px.Constant("France"),'code_departement'],
                 values='valeur_fonciere',
                 color='valeur_fonciere')
fig.update_layout(title='Carte proportionelle de la valeur foncière moyenne');
#fig.show()
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }

On s'aperçoit que la valeur foncière est fortement correlée avec la position géographique.

  1. Quelle est la surface réelle bâtie moyenne par département?
# Quelle est la surface réelle bâtie moyenne par département?
grouped_srb_dept = df[df['surface_reelle_bati'] > 0]
grouped_srb_dept = grouped_srb_dept.groupby('code_departement')['surface_reelle_bati'].mean().reset_index()
grouped_srb_dept['code_departement'] = grouped_srb_dept['code_departement'].astype('string')
fig = px.bar(grouped_srb_dept, y='surface_reelle_bati',
             x='code_departement',
             text_auto='.2s')
fig.update_layout(title="Surface réelle bâtie moyenne par departement", 
                  yaxis_title='Valeur foncière moyenne (€)', 
                  xaxis_title='Département');
#fig.show()
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }
  1. Quels sont les départements les plus chers pour l'immobilier en 2022 ?
# Quels sont les départements les plus chers pour l'immobilier en 2022 ?
grouped_vf_dept_top10 = grouped_vf_dept.sort_values('valeur_fonciere', ascending=False).head(10)

fig = px.bar(grouped_vf_dept_top10, x='valeur_fonciere', y='code_departement', orientation='h')

fig.update_layout(title='Les départements les plus chers pour l\'immobilier en 2022', 
                  xaxis_title='Valeur foncière moyenne (€)', 
                  yaxis_title='Département');
#fig.show()
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }
  1. Valeur foncière moyenne par jour en 2022
# Valeur foncière moyenne par jour en 2022
filtered_df = df[df['valeur_fonciere'] <= 4000000]
daily_means = filtered_df.groupby(filtered_df['date_mutation'].dt.date)['valeur_fonciere'].mean()

plt.scatter(daily_means.index, daily_means.values, c='red', label='Prix moyen')

avg_value = df['valeur_fonciere'].mean()
plt.axhline(y=avg_value, color='green', linestyle='solid', label='Valeur foncière moyenne sur 2022')

tick_dates = pd.date_range(start='2022-01-01', end='2022-12-31', freq='2M')
tick_labels = [date.strftime('%Y-%m') for date in tick_dates]
plt.xticks(ticks=tick_dates, labels = tick_labels, rotation=80)

plt.title('Valeur foncière moyenne par jour en 2022')
plt.xlabel("Date")
plt.ylabel("Valeur foncière moyenne")

plt.legend()
plt.show()
  1. Quelle est la valeur foncière moyenne à Paris en 2022 ?
#Quelle est la valeur foncière moyenne par commune dans le 75 en utilisant geojson et choropleth ?

geojson_url = "https://france-geojson.gregoiredavid.fr/repo/departements/75-paris/communes-75-paris.geojson"
geojson_data = requests.get(geojson_url).json()

vf_com_paris = df[(df['code_departement']==75) & df['valeur_fonciere'] > 0]
vf_com_paris = vf_com_paris.groupby('code_commune')['valeur_fonciere'].mean().reset_index()
vf_com_paris['code_commune'] = '75'+vf_com_paris['code_commune'].astype(str)

fig = px.choropleth(vf_com_paris, 
                    geojson=geojson_data, 
                    locations='code_commune', 
                    color='valeur_fonciere',
                    color_continuous_scale='Reds',
                    featureidkey='properties.code',
                    projection="mercator",
                    title="Valeur fonciére moyenne en €")
fig.update_geos(fitbounds="locations", visible=False)
fig.update_layout(height=600,
                  width=800);
#fig.show()
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }
  1. Quel est le prix moyen du mètre carré pour les appartements à Paris en 2022 ?
#Quelle est le prix moyen d'un mètre carré dans les communes du 75 en utilisant geojson et choropleth ?
geojson_url = "https://france-geojson.gregoiredavid.fr/repo/departements/75-paris/communes-75-paris.geojson"
geojson_data = requests.get(geojson_url).json()

vf_com_paris = df[(df['code_departement'] == 75) & (df['nombre_de_lots']<6) & ((df['surface_carrez_du_1er_lot'] + df['surface_carrez_du_2eme_lot'] + df['surface_carrez_du_3eme_lot'] + df['surface_carrez_du_4eme_lot'] + df['surface_carrez_du_5eme_lot']) > 0)]
vf_com_paris['surface_totale'] = vf_com_paris['surface_carrez_du_1er_lot'] + vf_com_paris['surface_carrez_du_2eme_lot'] + vf_com_paris['surface_carrez_du_3eme_lot'] + vf_com_paris['surface_carrez_du_4eme_lot'] + vf_com_paris['surface_carrez_du_5eme_lot']
vf_com_paris['prix_m2'] = vf_com_paris['valeur_fonciere'] / vf_com_paris['surface_totale']
vf_com_paris = vf_com_paris.groupby('code_commune')['prix_m2'].mean().reset_index()
vf_com_paris['code_commune'] = '75'+vf_com_paris['code_commune'].astype(str)

fig = px.choropleth(vf_com_paris, 
                    geojson=geojson_data, 
                    locations='code_commune', 
                    color='prix_m2',
                    color_continuous_scale='Reds',
                    featureidkey='properties.code',
                    projection="mercator",
                    title="Prix moyen d'un mètre carré en €")
fig.update_geos(fitbounds="locations", visible=False)
fig.update_layout(height=600,
                  width=800);
#fig.show()
%%jmd
[//]: # (-.-|m { input: true, output_error: false, input_fold: hide })
{ fig.to_html(include_plotlyjs=False, full_html=False) }
  1. Nombre de bien vendu dans les 20 villes
#Nombre de bien vendu dans les 20 villes
plt.rcParams['figure.figsize'] = [18, 5]
plt.rcParams['figure.dpi'] = 150

vente_ville = df.groupby(['commune']).size().sort_values(ascending = False).head(20)
x = vente_ville.index
y = vente_ville.tolist()

plt.scatter(x, y, color='#119670', marker='o', label = 'Nombre de biens vendus')
plt.title('Nombre de biens vendus par ville', fontsize = 13)
plt.xticks(rotation=60)
plt.xlabel("Ville", fontsize = 12)
plt.ylabel("Nombre de biens vendus", fontsize = 12)
plt.legend(loc = 'upper right')
plt.grid(True)
plt.show()

Lyon

  1. Valeur foncière moyenne par arrondissement de Lyon en 2022
#Valeur foncière moyenne par arrondissement de Lyon en 2022
lyon = df.loc[(df['commune'].str.contains("LYON")) & (df['commune'].str.contains("EME"))]
arrondissement_lyon = lyon.groupby(['commune']).mean().sort_values(['valeur_fonciere'])
x = arrondissement_lyon.index
y = arrondissement_lyon['valeur_fonciere']
arrondissement_lyon.head()
no_disposition valeur_fonciere no_voie code_postal code_commune no_plan surface_carrez_du_1er_lot surface_carrez_du_2eme_lot surface_carrez_du_3eme_lot surface_carrez_du_4eme_lot surface_carrez_du_5eme_lot nombre_de_lots code_type_local surface_reelle_bati nombre_pieces_principales surface_terrain
commune
LYON 5EME 1.004388 3.994591e+05 75.831055 69005.0 385.0 65.937591 19.938532 14.818713 0.382535 0.247450 0.000000 1.440761 2.592653 32.749325 1.309562 544.486726
LYON 8EME 1.002674 4.306062e+05 114.843302 69008.0 388.0 95.938235 29.448888 9.278094 0.381725 0.076824 0.000000 1.259626 2.613522 31.058805 1.145597 395.252427
LYON 2EME 1.034025 7.951936e+05 470.339226 69002.0 382.0 75.083817 31.912398 11.221286 2.977950 0.412515 0.581220 1.497925 2.587056 49.271650 1.314494 286.984615
LYON 4EME 1.021396 1.108314e+06 34.029296 69004.0 384.0 82.764640 22.410034 11.182523 1.084077 0.211948 0.000000 1.453829 2.598499 33.168230 1.225141 458.433333
LYON 7EME 1.006498 1.184941e+06 60.617319 69007.0 387.0 91.363890 25.497069 7.844611 0.545372 0.178652 0.006011 1.277327 2.615996 45.810305 1.099974 582.378788
#Valeur foncière moyenne par arrondissement de Lyon en 2022
plt.figure(1, figsize=(10, 6))
plt.plot(x, y, color='purple', marker='o', label='Prix moyen')
plt.title('Valeur fonciere moyenne par arrondissement de Lyon en 2021')
plt.xticks(rotation=80)
plt.xlabel("Arrondissements de Lyon")
plt.ylabel("Valeur fonciere moyenne")
plt.legend(loc = 'upper left')
plt.grid(True)
plt.show()
  1. Nombre de biens vendus par arrondissement de Lyon
# Nombre de biens vendus par arrondissement de Lyon
arrondissement_lyon = lyon.groupby(['commune']).size()
x = arrondissement_lyon.index.tolist()
y = arrondissement_lyon.tolist()
 
plt.figure(1, figsize=(10, 6))
plt.pie(y, labels = x, autopct = '%.2f')
plt.title("Pars de biens vendus par arrondissement à Lyon")

# Ajout d'un cercle au centre
my_circle=plt.Circle( (0,0), 0.7, color='white')
p=plt.gcf()
p.gca().add_artist(my_circle)

plt.show()

Relation diverse

  1. Nature des cultures en France en 2022
# Nature des cultures en France en 2022
plt.figure(figsize=(8,8))
plt.title('Nature des cultures françaises en 2022')
sns.set(rc={'figure.figsize':(3,9)})
sns.countplot(y='nature_culture', data=df)
<AxesSubplot:title={'center':'Nature des cultures françaises en 2022'}, xlabel='count', ylabel='nature_culture'>
  1. Relation entre valeur foncière et nature de mutation
# Relation entre valeur foncière et nature de mutation
df_ve = df[df['nature_mutation']=='Vente'].sort_values(by='valeur_fonciere', ascending=False)
se_vente_commune = df_ve.commune.value_counts()
plt.figure(figsize=(10,5))

df_best_city = df_ve[df_ve['commune'].isin(se_vente_commune.head(10).index)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] < df_best_city['valeur_fonciere'].quantile(.95)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] > df_best_city['valeur_fonciere'].quantile(.05)]
order=df_best_city['valeur_fonciere'].groupby(df_best_city.commune).median().sort_values(ascending=False)
plt.figure(figsize=(20,10))
ax = sns.boxplot(x=df_best_city.commune, y=df_best_city['valeur_fonciere'], order=order.index)

ax.set_title('Relation entre la commune et la valeur foncière')
ax.set_xlabel('Commune')
ax.set_ylabel('Valeur foncière')
Text(0, 0.5, 'Valeur foncière')
<Figure size 1500x750 with 0 Axes>
  1. Relation entre nombre de pièce principale et nature de mutation
# Relation entre nombre de pièce principale et nature de mutation

df_ve = df[df['nature_mutation']=='Vente'].sort_values(by='valeur_fonciere', ascending=False)
se_vente_nombre_pieces_principales = df_ve.nombre_pieces_principales.value_counts()
plt.figure(figsize=(10,5))

df_best_city = df_ve[df_ve['nombre_pieces_principales'].isin(se_vente_nombre_pieces_principales.head(10).index)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] < df_best_city['valeur_fonciere'].quantile(.95)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] > df_best_city['valeur_fonciere'].quantile(.05)]
order=df_best_city['valeur_fonciere'].groupby(df_best_city.nombre_pieces_principales).median().sort_values(ascending=False)
plt.figure(figsize=(20,10))
ax = sns.boxplot(x=df_best_city.nombre_pieces_principales, y=df_best_city['valeur_fonciere'], order=order.index)

ax.set_title('Relation entre le nombre pièce principale et la valeur foncière')
ax.set_xlabel('nombre_pieces_principales')
ax.set_ylabel('Valeur foncière')
Text(0, 0.5, 'Valeur foncière')
<Figure size 1500x750 with 0 Axes>
  1. Prix au m² selon le type de local ?
# Prix au mètre carré en fonction du type de local
pm2 = df[(df['nombre_de_lots']<6) & ((df['surface_carrez_du_1er_lot'] + df['surface_carrez_du_2eme_lot'] + df['surface_carrez_du_3eme_lot'] + df['surface_carrez_du_4eme_lot'] + df['surface_carrez_du_5eme_lot']) > 0)]
pm2['surface_totale'] = pm2['surface_carrez_du_1er_lot'] + pm2['surface_carrez_du_2eme_lot'] + pm2['surface_carrez_du_3eme_lot'] + pm2['surface_carrez_du_4eme_lot'] + pm2['surface_carrez_du_5eme_lot']
pm2['prix_m2'] = pm2['valeur_fonciere'] / pm2['surface_totale']
sns.set(rc={'figure.figsize':(40,30)})
sns.color_palette()
sns.catplot(x="type_local", y="prix_m2", jitter=True, data=pm2, kind="strip", height=8, aspect=1.5, palette="Set2")
<seaborn.axisgrid.FacetGrid at 0x7fe8a3fa4160>
  1. Prix au m² selon le nombre de pièce principale
# Prix au mètre carré en fonction du nombre de pièce principale
pm2 = df[(df['nombre_de_lots']<6) & ((df['surface_carrez_du_1er_lot'] + df['surface_carrez_du_2eme_lot'] + df['surface_carrez_du_3eme_lot'] + df['surface_carrez_du_4eme_lot'] + df['surface_carrez_du_5eme_lot']) > 0)]
pm2['surface_totale'] = pm2['surface_carrez_du_1er_lot'] + pm2['surface_carrez_du_2eme_lot'] + pm2['surface_carrez_du_3eme_lot'] + pm2['surface_carrez_du_4eme_lot'] + pm2['surface_carrez_du_5eme_lot']
pm2['prix_m2'] = pm2['valeur_fonciere'] / pm2['surface_totale']
pm2['nombre_pieces_principales'] = pm2['nombre_pieces_principales'].astype('category')
sns.set(rc={'figure.figsize':(40,30)})
sns.color_palette()
sns.catplot(x="nombre_pieces_principales", y="prix_m2", jitter=True, data=pm2, kind="strip", height=8, aspect=1.5, palette="Set2")
<seaborn.axisgrid.FacetGrid at 0x7fe8838d8790>

IV ] Comparaison avec 2021

Importation et nettoyage des données de 2021

df2021 = pd.read_csv('https://static.data.gouv.fr/resources/demandes-de-valeurs-foncieres/20230405-155828/valeursfoncieres-2021.txt', sep = '|')
df2021 = df2021.rename(columns=lambda x: x.replace(' ', '_').lower())
df2021 = df2021.drop(['identifiant_de_document',
              'reference_document',
              '1_articles_cgi',
              '2_articles_cgi',
              '3_articles_cgi',
              '4_articles_cgi',
              '5_articles_cgi',
              'prefixe_de_section',
              'no_volume',
              '3eme_lot',
              '4eme_lot',
              '5eme_lot',
              'identifiant_local',
              'nature_culture_speciale',
              ],axis= 1)
# suppression des doubles
df2021 = df2021.drop_duplicates()
# suppression des ligne null
df2021 = df2021.dropna(how="all")
df2021 = df2021.drop_duplicates()

df2021['valeur_fonciere'] = df2021['valeur_fonciere'].str.replace(',', '.').astype('float')
df2021['surface_carrez_du_1er_lot'] = df2021['surface_carrez_du_1er_lot'].str.replace(',', '.').astype('float')
df2021['surface_carrez_du_2eme_lot'] = df2021['surface_carrez_du_2eme_lot'].str.replace(',', '.').astype('float')
df2021['surface_carrez_du_3eme_lot'] = df2021['surface_carrez_du_3eme_lot'].str.replace(',', '.').astype('float')
df2021['surface_carrez_du_4eme_lot'] = df2021['surface_carrez_du_4eme_lot'].str.replace(',', '.').astype('float')
df2021['surface_carrez_du_5eme_lot'] = df2021['surface_carrez_du_5eme_lot'].str.replace(',', '.').astype('float')
df2021.info()
df2021.head()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4303715 entries, 0 to 4649208
Data columns (total 29 columns):
 #   Column                      Dtype  
---  ------                      -----  
 0   no_disposition              int64  
 1   date_mutation               object 
 2   nature_mutation             object 
 3   valeur_fonciere             float64
 4   no_voie                     float64
 5   b/t/q                       object 
 6   type_de_voie                object 
 7   code_voie                   object 
 8   voie                        object 
 9   code_postal                 float64
 10  commune                     object 
 11  code_departement            object 
 12  code_commune                int64  
 13  section                     object 
 14  no_plan                     int64  
 15  1er_lot                     object 
 16  surface_carrez_du_1er_lot   float64
 17  2eme_lot                    object 
 18  surface_carrez_du_2eme_lot  float64
 19  surface_carrez_du_3eme_lot  float64
 20  surface_carrez_du_4eme_lot  float64
 21  surface_carrez_du_5eme_lot  float64
 22  nombre_de_lots              int64  
 23  code_type_local             float64
 24  type_local                  object 
 25  surface_reelle_bati         float64
 26  nombre_pieces_principales   float64
 27  nature_culture              object 
 28  surface_terrain             float64
dtypes: float64(12), int64(4), object(13)
memory usage: 985.0+ MB
no_disposition date_mutation nature_mutation valeur_fonciere no_voie b/t/q type_de_voie code_voie voie code_postal ... surface_carrez_du_3eme_lot surface_carrez_du_4eme_lot surface_carrez_du_5eme_lot nombre_de_lots code_type_local type_local surface_reelle_bati nombre_pieces_principales nature_culture surface_terrain
0 1 05/01/2021 Vente 185000.0 5080.0 NaN CHE 0471 DE VOGELAS 1370.0 ... NaN NaN NaN 0 1.0 Maison 97.0 5.0 S 2410.0
1 1 05/01/2021 Vente 185000.0 5080.0 NaN CHE 0471 DE VOGELAS 1370.0 ... NaN NaN NaN 0 3.0 Dépendance 0.0 0.0 S 2410.0
2 1 06/01/2021 Vente 10.0 NaN NaN NaN B043 ROUGEMONT 1290.0 ... NaN NaN NaN 0 NaN NaN NaN NaN BT 530.0
3 1 04/01/2021 Vente 204332.0 7.0 NaN ALL 0276 DES ECUREUILS 1310.0 ... NaN NaN NaN 0 1.0 Maison 88.0 4.0 S 866.0
4 1 06/01/2021 Vente 320000.0 87.0 NaN RTE 0140 DE CERTINES 1250.0 ... NaN NaN NaN 0 1.0 Maison 168.0 5.0 S 1426.0

5 rows × 29 columns

  1. Comparaison du prix moyen du mètre carré entre 2021 et 2022
pm2_22 = df[(df['nombre_de_lots']<6) & ((df['surface_carrez_du_1er_lot'] + df['surface_carrez_du_2eme_lot'] + df['surface_carrez_du_3eme_lot'] + df['surface_carrez_du_4eme_lot'] + df['surface_carrez_du_5eme_lot']) > 0)]
pm2_22['surface_totale'] = pm2_22['surface_carrez_du_1er_lot'] + pm2_22['surface_carrez_du_2eme_lot'] + pm2_22['surface_carrez_du_3eme_lot'] + pm2_22['surface_carrez_du_4eme_lot'] + pm2_22['surface_carrez_du_5eme_lot']
pm2_22['prix_m2'] = pm2_22['valeur_fonciere'] / pm2_22['surface_totale']

pm2_21 = df2021[(df2021['nombre_de_lots']<6) & ((df2021['surface_carrez_du_1er_lot'] + df2021['surface_carrez_du_2eme_lot'] + df2021['surface_carrez_du_3eme_lot'] + df2021['surface_carrez_du_4eme_lot'] + df2021['surface_carrez_du_5eme_lot']) > 0)]
pm2_21['surface_totale'] = pm2_21['surface_carrez_du_1er_lot'] + pm2_21['surface_carrez_du_2eme_lot'] + pm2_21['surface_carrez_du_3eme_lot'] + pm2_21['surface_carrez_du_4eme_lot'] + pm2_21['surface_carrez_du_5eme_lot']
pm2_21['prix_m2'] = pm2_21['valeur_fonciere'] / pm2_21['surface_totale']


fig = plt.figure(11,figsize = (10,5))
axis = fig.add_subplot(1, 1, 1)
axis.set_title('Comparaison du prix du mètre carré entre 2021 et 2022')
axis.set_xlabel("Année")
axis.set_ylabel("Prix")

gb1 = pm2_21['prix_m2'].mean()

gb2 = pm2_22['prix_m2'].mean()

com = ['2021','2022']
prix = [gb1,gb2]

axis.bar(com[:],prix[:])

plt.xticks(ticks=com,labels=prix,rotation=0)
fig.show()

On remarque que la valeur foncière moyenne est plus haute sur l'année 2022 que sur l'année 2021.

  1. Comparaison de la nature des mutations
mutation_type2021 = df2021['nature_mutation']
r2021 = Counter(mutation_type2021)
mutation_type2022 = df['nature_mutation']
r2022 = Counter(mutation_type2022)


mutation_df2021 = pd.DataFrame.from_dict(r2021, orient='index').sort_values(by=0)
mutation_df2021.columns = ['nature_mutation']

mutation_df2022 = pd.DataFrame.from_dict(r2022, orient='index').sort_values(by=0)
mutation_df2022.columns = ['nature_mutation']

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(32, 8))

mutation_df2021.plot.pie(y = 'nature_mutation', 
                 colormap = 'Reds_r',
                 figsize = (16, 16),
                 fontsize = 9, 
                 autopct = '%.2f',
                 legend = False,
                 title = 'Diagramme de distribution de la nature des mutations en 2021',
                 ax=ax1)


mutation_df2022.plot.pie(y = 'nature_mutation', 
                 colormap = 'Reds_r',
                 figsize = (16, 16),
                 fontsize = 9, 
                 autopct = '%.2f',
                 legend = False,
                 title = 'Diagramme de distribution de la nature des mutations 2022',
                 ax=ax2,
                 )



# Ajouter un cercle au centre pour faire un donut chart
mutation_df2021=plt.Circle( (0,0), 0.7, color='white')
mutation_df2022=plt.Circle( (0,0), 0.7, color='white')

plt.show()

On remarque qu'il n'y a presque pas de différence dans la répartition des natures de mutation entre l'année 2021 et 2022

On créé un nouveau dataframe rassemblant les donnée de 2021 et 2022

df['year'] = int(2022)
df2021['year'] = int(2021)
all_years = [ df, df2021]
data_years = pd.concat(all_years)
  1. Surface du terrain en fonction du département entre 2021 et 2022
fig = plt.figure(4,figsize = (35,10))
axis = fig.add_subplot(1, 1, 1)
axis.set_title('Surface du terrain en fonction du département entre 2021 et 2022')
axis.set_xlabel("Département")
axis.set_ylabel("Surface du terrain")
gb = data_years.loc[data_years["code_departement"].notna(),("surface_terrain","code_departement","year")]

ax = sns.barplot(x=gb["code_departement"].astype(str), y=gb["surface_terrain"], hue="year", data = gb)

plt.xticks(rotation=90)
fig.show()
  1. Relation entre la commune et la valeur foncière en fonction de la commune
sns.set_theme(style="ticks", palette="pastel")
df_ve = data_years[data_years['nature_mutation']=='Vente'].sort_values(by='valeur_fonciere', ascending=False)
se_vente_commune = df_ve.commune.value_counts()
plt.figure(figsize=(10,5))

df_best_city = df_ve[df_ve['commune'].isin(se_vente_commune.head(10).index)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] < df_best_city['valeur_fonciere'].quantile(.95)]
df_best_city = df_best_city[df_best_city['valeur_fonciere'] > df_best_city['valeur_fonciere'].quantile(.05)]
order=df_best_city['valeur_fonciere'].groupby(df_best_city.commune).median().sort_values(ascending=False)
plt.figure(figsize=(20,10))
ax = sns.boxplot(x=df_best_city.commune, y=df_best_city['valeur_fonciere'], hue=df_best_city['year'], order=order.index, palette=["m", "g"],)
plt.legend(loc = 'upper right')

ax.set_title('Relation entre la commune et la valeur foncière')
ax.set_xlabel('Commune')
ax.set_ylabel('Valeur foncière')
Text(0, 0.5, 'Valeur foncière')
<Figure size 1500x750 with 0 Axes>
  1. Nombre de biens vendus par commune en 2022 et 2021
sns.set_style('whitegrid')
sns.set(rc={'figure.figsize':(18,5), 'figure.dpi': 150})

vente_ville = data_years.groupby(['commune','year']).size().sort_values(ascending=False).head(20).reset_index(name='nombre')
ax = sns.scatterplot(x='commune', y='nombre', hue='year', data=vente_ville, color='#119670', palette=["b", "r"], marker='o')
ax.set_title('Nombre de biens vendus par commune en 2022 et 2021')
ax.set_xlabel('Commune')
ax.set_ylabel('Nombre de biens')
Text(0, 0.5, 'Nombre de biens')

On remarque que les villes dans lequel le plus de transaction ont été fait sont différente entre 2021 et 2022


*Licence :* Licence Ouverte / Open Licence version 2.0

Logo-licence-ouverte2.png